﻿using System;
using System.Diagnostics;
using System.Windows.Input;

namespace NFox.WPF
{
    /// <summary>
    /// 命令基类
    /// </summary>
    /// <seealso cref="System.Windows.Input.ICommand" />
    public class RelayCommand : ICommand
    {
        readonly Func<object, bool> _canExecute;
        readonly Action<object> _execute;
        /// <summary>
        /// 初始化 <see cref="RelayCommand"/> 类.
        /// </summary>
        /// <param name="execute">执行函数</param>
        public RelayCommand(Action<object> execute):this(execute,null)
        {

        }
        /// <summary>
        /// 初始化 <see cref="RelayCommand"/> 类.
        /// </summary>
        /// <param name="execute">执行函数委托</param>
        /// <param name="canExecute">是否可执行函数委托</param>
        /// <exception cref="ArgumentNullException">execute</exception>
        public RelayCommand(Action<object> execute,Func<object,bool> canExecute)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }

        /// <summary>
        /// 当出现影响是否应执行该命令的更改时发生。
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                {
                    CommandManager.RequerySuggested += value;
                }
            }
            remove
            {
                if (_canExecute != null)
                {
                    CommandManager.RequerySuggested -= value;
                }
            }
        }
        /// <summary>
        /// 定义确定此命令是否可在其当前状态下执行的方法。
        /// </summary>
        /// <param name="parameter">此命令使用的数据。  如果此命令不需要传递数据，则该对象可以设置为 <see langword="null" />。</param>
        /// <returns>
        /// 如果可执行此命令，则为 <see langword="true" />；否则为 <see langword="false" />。
        /// </returns>
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }
        /// <summary>
        /// 定义在调用此命令时要调用的方法。
        /// </summary>
        /// <param name="parameter">此命令使用的数据。  如果此命令不需要传递数据，则该对象可以设置为 <see langword="null" />。</param>
        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}
